package com.keta.foundation.dataFilter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.ServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.web.tags.HasPermissionTag;
import org.springframework.data.jpa.domain.Specification;

import com.keta.foundation.constants.Constants;
import com.keta.foundation.util.ConvertUtil;
import com.keta.foundation.util.ServletUtils;

public class DynamicSpecifications {

	/**
	 * 获取搜索过滤器
	 * 
	 * @param request
	 */
	public static Collection<DataFilter> genSearcheFilter(ServletRequest request) {
		Map<String, Object> searchParams = ServletUtils.getParametersStartingWith(request, Constants.SEARCH_PREFIX);
		return DataFilter.paser(searchParams).values();
	}

	/**
	 * 获取数据权限过滤器，在页面中的隐藏域实现 在数据权限拦截中往request对象中加入DataFilter
	 */
	public static Collection<DataFilter> genDataControlFilter(ServletRequest request) {
		// 留到后面实现
		return null;
	}

	/**
	 * 生成spring data jpa 的过滤对象Specification<T>
	 */
	public static <T> Specification<T> byDataFilter(ServletRequest request, Class<T> entityClazz,
			DataFilter... dataFilters) {
		// 加入自定义的DataFilter
		Collection<DataFilter> customFilters = new HashSet<DataFilter>();
		for (DataFilter filter : dataFilters) {
			customFilters.add(filter);
		}
		return byDataFilter(request, entityClazz, customFilters);
	}

	/**
	 * 生成spring data jpa 的过滤对象Specification<T>
	 */
	public static <T> Specification<T> byDataFilter(ServletRequest request, Class<T> entityClazz,
			Collection<DataFilter> customFilters) {
		// 此处的DataFilter由三部分构成: 搜索过滤器 数据权限过滤器 代码中自定义过滤器
		final HashSet<DataFilter> filterSet = new HashSet<DataFilter>();

		Collection<DataFilter> searcheFilters = genSearcheFilter(request);
		// Collection<DataFilter> dataControlFilters =
		// genDataControlFilter(request);

		filterSet.addAll(searcheFilters);
		// filterSet.addAll(dataControlFilters);
		filterSet.addAll(customFilters);

		return new Specification<T>() {
			@SuppressWarnings("unchecked")
			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder builder) {

				if (filterSet != null && !filterSet.isEmpty()) {

					List<Predicate> predicates = new ArrayList<Predicate>();

					for (DataFilter filter : filterSet) {
						// nested path translate, 如Task的名为"user.name"的filedName,
						// 转换为Task.user.name属性
						String[] names = StringUtils.split(filter.getFieldName(), ".");
						Path expression = root.get(names[0]);
						for (int i = 1; i < names.length; i++) {
							expression = expression.get(names[i]);
						}

						// 自动进行enum和date的转换。
						Class clazz = expression.getJavaType();
						if (Date.class.isAssignableFrom(clazz) && !filter.getValue().getClass().equals(clazz)) {
							System.out.println(ConvertUtil.convert2Date((String) filter.getValue()));
							filter.setValue(ConvertUtil.convert2Date((String) filter.getValue()));
						} else if (Enum.class.isAssignableFrom(clazz) && !filter.getValue().getClass().equals(clazz)) {
							filter.setValue(ConvertUtil.convert2Enum(clazz, (String) filter.getValue()));
						}

						switch (filter.getOperator()) {
						case EQ:
							predicates.add(builder.equal(expression, filter.getValue()));
							break;
						case NEQ:
							predicates.add(builder.notEqual(expression, filter.getValue()));
							break;
						case LIKE:
							predicates.add(builder.like(expression, "%" + filter.getValue() + "%"));
							break;
						case GT:
							predicates.add(builder.greaterThan(expression, (Comparable) filter.getValue()));
							break;
						case LT:
							predicates.add(builder.lessThan(expression, (Comparable) filter.getValue()));
							break;
						case GTE:
							predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.getValue()));
							break;
						case LTE:
							predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.getValue()));
							break;
						case IN:
							predicates.add(builder.and(expression.in((Object[]) filter.getValue())));
							break;
						}
					}
					// 将所有条件用 and 联合起来
					if (predicates.size() > 0) {
						return builder.and(predicates.toArray(new Predicate[predicates.size()]));
					}
				}
				return builder.conjunction();
			}
		};
	}

}
